package com.beone.admin.annotation;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotations.TableId;
import com.base.common.BaseModel;
import com.base.common.RequestContextUtils;
import com.beone.admin.controller.ControllerUtils;
import com.beone.admin.entity.BaseUser;
import com.beone.admin.entity.SysLog;
import com.beone.admin.mapper.SysLogMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;


/**
 * @title  为增删改添加日志监控
 * @Author 覃球球
 * @Version 1.0 on 2018/4/28.
 * @Copyright 长笛龙吟
 */
@Aspect
@Component
public class LogAspect {

    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    private SysLogMapper logMapper;

    @Pointcut("@annotation(com.beone.admin.annotation.Log)")
    private void pointcut() {

    }

    @Before("pointcut()")
    public void insertLogSuccess(JoinPoint jp) {
        addLog(jp, getDesc(jp));
    }

    private void addLog(JoinPoint jp, String text) {
        Log.LOG_TYPE type = getType(jp);
        SysLog log = new SysLog();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //一些系统监控
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes)
                    RequestContextHolder.getRequestAttributes()).getRequest();
            String ip = RequestContextUtils.getClientIp(request);
            log.setIp(ip);

            BaseUser currentUser = ControllerUtils.getAdminUser(request);
            if(currentUser != null){
                log.setUsername(currentUser.getUserName());
            }
        }
        log.setCreateTime(new Date());
        log.setType(type.toString());
        log.setContent(text);

        Object[] obj = jp.getArgs();
        StringBuffer buffer = new StringBuffer();
        if (obj != null) {
            buffer.append("[参数");
            for (int i = 0; i < obj.length; i++) {
                if(i > 0){
                    buffer.append(",");
                }
                buffer.append((i + 1) + " : ");
                Object o = obj[i];
                if(o instanceof Model || o instanceof HttpServletRequest
                        || o instanceof HttpServletResponse){
                    continue;
                }else if(o instanceof BaseModel){
                    Object primaryKey = getPrimaryKey((BaseModel) o);
                    if(primaryKey != null){
                         log.setContent("修改" + log.getContent());
                    }else {
                        log.setContent("新增" + log.getContent());
                    }
                }
                String parameter=null;
                try {
                    parameter= JSON.toJSONString(o);
                }catch (Exception e){
                    continue;
                }
                buffer.append(parameter);
            }
            buffer.append("]");
        }
        log.setParam(buffer.toString());

        if(logger.isDebugEnabled()){
            logger.debug("日志处理： {}", JSON.toJSONString(log));
        }
        logMapper.insert(log);
    }

    /**
     * 获取主键值
     * @param entity
     * @return
     */
    private Object getPrimaryKey(BaseModel entity){
        Field[] fields = entity.getClass().getDeclaredFields();
        Field item = null;
        for (int i = 0; i < fields.length; i++) {
            TableId id = fields[i].getAnnotation(TableId.class);
            if(id != null){
                item = fields[i];
                break;
            }
        }


        if(item == null){
            return null;
        }

        item.setAccessible(true);
        return ReflectionUtils.getField(item, entity);
    }

    /**
     * 记录异常
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void afterException(JoinPoint joinPoint, Exception e) {
        logger.warn("-----------afterException: {}", e.getMessage());
        addLog(joinPoint, getDesc(joinPoint) + e.getMessage());
    }


    private String getDesc(JoinPoint joinPoint) {
        MethodSignature methodName = (MethodSignature) joinPoint.getSignature();
        Method method = methodName.getMethod();
        return method.getAnnotation(Log.class).desc();
    }

    private Log.LOG_TYPE getType(JoinPoint joinPoint) {
        MethodSignature methodName = (MethodSignature) joinPoint.getSignature();
        Method method = methodName.getMethod();
        return method.getAnnotation(Log.class).type();
    }
}